﻿
using System.Runtime.CompilerServices;

namespace TotalApplication.Core
{
    public class BaseLogFactory : ILogFactory
    {
        #region Constructor

        /// <summary>
        /// Default constructor
        /// </summary>
        public BaseLogFactory()
        {
            // Default add a console logger
            AddLogger(new ConsoleLoggers());
        }

        #endregion

        #region Protected Properties

        protected List<ILogger> _loggers = new List<ILogger>();

        /// <summary>
        /// A lock for the logger list to keep it thread-safe
        /// </summary>
        protected object _loggersLock = new object();

        #endregion

        #region Public Properties

        public LogFactoryLevel LogOutPutLevel { get; set; }

        /// <summary>
        /// If true, includes the origin of where the log message was logged from
        /// such as the class name, line number and fileName
        /// </summary>
        public bool IncludeLogOriginDetails { get; set; }

        #endregion

        #region Events

        public event Action<(string message, LogFactoryLevel level)> NewLog = (details) => { };

        #endregion

        #region Methods

        public void AddLogger(ILogger logger)
        {
            lock (_loggersLock)
            {
                if(!_loggers.Contains(logger))
                    _loggers.Add(logger);
            }
        }

        public void Log(
            string message, 
            LogFactoryLevel level = LogFactoryLevel.Informative, 
            [CallerMemberName]string origin = "", 
            [CallerFilePath]string filePath = "", 
            [CallerLineNumber]int LineNumber = 0)
        {
            if (IncludeLogOriginDetails)
                message = $"[{Path.GetFileName(filePath)} > {origin}() > Line {LineNumber}]{Environment.NewLine}{message}";

            _loggers.ForEach(logger => logger.Log(message, level));

            // Inform listeners
            NewLog.Invoke((message, level));
        }

        public void RemoveLogger(ILogger logger)
        {
            lock (_loggersLock)
            {
                if (!_loggers.Contains(logger))
                    _loggers.Remove(logger);
            }
        }

        #endregion
    }
}
